﻿// *********************************
// Message from Original Author:
//
// 2008 Jose Menendez Poo
// Please give me credit if you use this code. It's all I ask.
// Contact me for more info: menendezpoo@gmail.com
// *********************************
//
// Original project from http://ribbon.codeplex.com/
// Continue to support and maintain by http://officeribbon.codeplex.com/

using System.ComponentModel;
using System.Drawing;

namespace System.Windows.Forms
{
    public class RibbonHost : RibbonItem
    {
        private Control ctl;
        private Font ctlFont;
        private Size ctlSize;
        private RibbonElementSizeMode _lastSizeMode;
        public event MouseEventHandler ClientMouseMove;

        /// <summary>
        /// Occurs when the SizeMode of the controls container is changing. if you manually set the size of the control you need to set the Handled flag to true.
        /// </summary>
        [Description("Occurs when the SizeMode of the Controls container is changing. if you manually set the size of the control you need to set the Handled flag to true.")]
        public event RibbonHostSizeModeHandledEventHandler SizeModeChanging;
        public delegate void RibbonHostSizeModeHandledEventHandler(object sender, RibbonHostSizeModeHandledEventArgs e);

        /// <summary>
        /// Gets or sets the control that this item will host
        /// </summary>
        public Control HostedControl
        {
            get => ctl;
            set
            {
                ctl = value;
                NotifyOwnerRegionsChanged();

                //_mouseHook = new RibbonHelpers.GlobalHook(RibbonHelpers.GlobalHook.HookTypes.Mouse);
                //_mouseHook.MouseDown += new MouseEventHandler(_mouseHook_MouseDown);
                //_mouseHook.MouseUp += new MouseEventHandler(_mouseHook_MouseUp);

                if (ctl != null && Site == null)
                {
                    //changing the owner changes the font so let save it for future use
                    ctlFont = ctl.Font;
                    ctlSize = ctl.Size;

                    //hook into some needed events
                    ctl.MouseMove += ctl_MouseMove;
                    CanvasChanged += RibbonHost_CanvasChanged;
                    //we must know when our tab changes so we can hide the control
                    if (OwnerTab != null)
                        Owner.ActiveTabChanged += Owner_ActiveTabChanged;

                    //the control must always have the same parent as the host item so set it here.
                    if (Owner != null)
                        Owner.Controls.Add(ctl);

                    ctl.Font = ctlFont;

                    /*Initially set the control to be hidden. If it needs to be displayed immediately it will get set in the
                     * placecontrol function. This was located at the top of the function, however it caused the control 
                     * if located on a dropdown to not appear the correct size. A second showing fixed the issue. Seems to
                     * because the control is added to the ribbon while invisible??? */
                    ctl.Visible = false;

                }
            }
        }

        /// <summary>
        /// Raises the paint event and draws the control
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public override void OnPaint(object sender, RibbonElementPaintEventArgs e)
        {
            if (Owner != null)
            {
                StringFormat f = StringFormatFactory.CenterNoWrap(StringTrimming.None);
                if (Site != null && Site.DesignMode)
                {
                    Owner.Renderer.OnRenderRibbonItemText(new RibbonTextEventArgs(Owner, e.Graphics, Bounds, this, Bounds, Site.Name, f));
                }
                else
                {
                    Owner.Renderer.OnRenderRibbonItemText(new RibbonTextEventArgs(Owner, e.Graphics, Bounds, this, Bounds, Text, f));
                    if (ctl != null)
                    {
                        if (ctl.Parent != Canvas)
                            Canvas.Controls.Add(ctl);

                        //time to show our control
                        ctl.Location = new Point(Bounds.Left, (SizeMode == RibbonElementSizeMode.DropDown) ? Bounds.Top : Bounds.Top);
                        ctl.Visible = true;
                        ctl.BringToFront();
                    }
                }
            }
        }

        /// <summary>
        /// Sets the bounds of the panel
        /// </summary>
        /// <param name="bounds"></param>
        public override void SetBounds(Rectangle bounds)
        {
            base.SetBounds(bounds);
        }
        /// <summary>
        /// Measures the size of the panel on the mode specified by the event object
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <returns></returns>
        /// 
        public override Size MeasureSize(object sender, RibbonElementMeasureSizeEventArgs e)
        {
            if (Site != null && Site.DesignMode && Owner != null)
            {
                //when in design mode just paint the name of this control
                int Width = Convert.ToInt32(e.Graphics.MeasureString(Site.Name, Owner.Font).Width);
                int Height = 20;
                SetLastMeasuredSize(new Size(Width, Height));
            }
            else if (ctl == null || !Visible)
                SetLastMeasuredSize(new Size(0, 0));
            else
            {
                ctl.Visible = false;
                if (_lastSizeMode != e.SizeMode)
                {
                    _lastSizeMode = e.SizeMode;
                    RibbonHostSizeModeHandledEventArgs hev = new RibbonHostSizeModeHandledEventArgs(e.Graphics, e.SizeMode);
                    OnSizeModeChanging(ref hev);
                }
                SetLastMeasuredSize(new Size(ctl.Size.Width, ctl.Size.Height));
            }
            return LastMeasuredSize;
        }

        /// <summary>
        /// Call this method when you need to close a popup that the control is contained in
        /// </summary>
        public void HostCompleted()
        {
            //Kevin Carbis - Clear everything by simulating the click event on the parent item
            //just in case we are in a popup window
            OnClick(new MouseEventArgs(MouseButtons.Left, 1, Cursor.Position.X, Cursor.Position.Y, 0));
        }

        /// <summary>
        /// Raises the <see cref="SizeModeChanging"/> event
        /// </summary>
        /// <param name="e"></param>
        public virtual void OnSizeModeChanging(ref RibbonHostSizeModeHandledEventArgs e)
        {
            if (SizeModeChanging != null)
            {
                SizeModeChanging(this, e);
            }
        }

        private void PlaceControls()
        {
            if (ctl != null && Site == null)
            {
                ctl.Location = new Point(Bounds.Left + 1, Bounds.Top + 1);
                //if we are located directly in a panel then we need to make sure the panel is not in overflow
                //mode or we will look bad showing on the panel when we shouldn't be
                if ((Canvas is Ribbon) && (OwnerPanel != null && OwnerPanel.SizeMode == RibbonElementSizeMode.Overflow))
                    ctl.Visible = false;
            }
        }

        private void ctl_MouseMove(object sender, MouseEventArgs e)
        {
            // Note: Unlike all other Ribbon components, e.X and e.Y coordinates are based on the controls Top and Left, not the Ribbons.

            //Console.WriteLine(e.Location.ToString());

            /* If control is on the Ribbon send the mouse move event to the Ribbon directly, converting from
             * control coordinates to Ribbon coordinates. */
            if (OwnerItem == null)
            {
                MouseEventArgs eRibbonArgs = new MouseEventArgs(e.Button, e.Clicks,
                    Owner.PointToClient(ctl.PointToScreen(e.Location)).X,
                    Owner.PointToClient(ctl.PointToScreen(e.Location)).Y, e.Delta);
                /* This should probably raise an event, however there is no reference to hosted controls on the Ribbon.
                 * In the future, probably better to have a control collection for hosted controls on the Ribbon and monitor the
                 * mousemove there and filter down. */
                Owner.OnRibbonHostMouseMove(eRibbonArgs);
            }
            else
            {
                // Raise MouseMove event to any container (i.e. containing DropDown).
                MouseEventArgs eContArgs = new MouseEventArgs(e.Button, e.Clicks, Bounds.Left + e.X, Bounds.Top + e.Y, e.Delta);
                if (ClientMouseMove != null)
                    ClientMouseMove(this, eContArgs);
            }

            OnMouseMove(e);

        }

        private void Owner_ActiveTabChanged(object sender, EventArgs e)
        {
            //hide this control if our tab is not the active tab
            if (ctl != null && OwnerTab != null && Owner.ActiveTab != OwnerTab)
                ctl.Visible = false;
        }
        private void RibbonHost_CanvasChanged(object sender, EventArgs e)
        {
            if (ctl != null)
            {
                Canvas.Controls.Add(ctl);
                ctl.Font = ctlFont;
                //ctl.Location = new System.Drawing.Point(Bounds.Left + 1, Bounds.Top + 1);
            }
        }
        internal override void SetSizeMode(RibbonElementSizeMode sizeMode)
        {
            base.SetSizeMode(sizeMode);
            if (ctl != null && OwnerPanel != null && OwnerPanel.SizeMode == RibbonElementSizeMode.Overflow)
            {
                ctl.Visible = false;
            }
        }
    }
}
